home *** CD-ROM | disk | FTP | other *** search
Oberon Text | 1995-10-27 | 17.4 KB | 421 lines | [TEXT/.Ob4] |
- Syntax10.Scn.Fnt
- StampElems
- Alloc
- 27 Oct 95
- InfoElems
- Alloc
- Syntax10.Scn.Fnt
- StampElems
- Alloc
- 27 Oct 95
- "Title": Run time debugger
- "Author": mah
- "Abstract": trap handler & lowlevel processor handling
- "Keywords":
- "Version":
- "From": 25.10.94 16:53:38
- "Until":
- "Changes":
- 10.12.94 separate codeseg for restart instead of removing one trap instr
- 26.1.95 separate debugging stack
- 5.4.95 error fixed with local pointers on stack resp. in register
- ParcElems
- Alloc
- Syntax10b.Scn.Fnt
- Syntax10i.Scn.Fnt
- FoldElems
- Syntax10.Scn.Fnt
- Syntax10b.Scn.Fnt
- Syntax10i.Scn.Fnt
- up*: Proc; (* caller of myself *)
- pc*, sp*: LONGINT;
- name*: ARRAY 64 OF CHAR;
- modName*: ARRAY 32 OF CHAR;
- regs*: Sys.ExceptionInfo;
- beginPC*, endPC*: LONGINT
- END;
- Syntax10.Scn.Fnt
- Syntax10i.Scn.Fnt
- (* stack copy *)
- size: LONGINT; (* size of currently saved stack *)
- adr: LONGINT; (* Adress of memory block for debug stack *)
- p: POINTER TO ARRAY OF CHAR (* Adress of memory block as pointer *)
- END;
- Syntax10.Scn.Fnt
- VAR a: LONGINT;
- BEGIN
- a := adr - Kernel.resumeSP + stack.adr;
- IF (a < stack.adr) & (a >= stack.adr - stack.size) THEN adr := a END
- END ConvertAdr;
- Syntax10.Scn.Fnt
- VAR n : LONGINT; shift : SHORTINT; x : CHAR;
- BEGIN
- shift := 0; n := 0; SYS.GET (refs, x); INC (refs);
- WHILE ORD(x)>=128 DO
- INC (n, ASH (ORD (x) MOD 128, shift));
- INC (shift, 7);
- SYS.GET (refs, x); INC (refs)
- END;
- k := n + ASH (ORD (x) MOD 64, shift) - ASH (ORD (x) DIV 64, shift) * 64
- END RInt;
- Syntax10.Scn.Fnt
- VAR i : INTEGER; ch : CHAR;
- BEGIN i := 0; REPEAT SYS.GET (refs, ch); name[i] := ch; INC (i); INC (refs) UNTIL ch = 0X
- END RName;
- Syntax10.Scn.Fnt
- BEGIN
- IF dest = NIL THEN NEW (dest); NEW (dest.spec); NEW (dest.reg); NEW (dest.fp) END;
- dest.kind := src.kind;
- dest.spec^ := src.spec^; dest.reg^ := src.reg^; dest.fp^ := src.fp^
- END MoveRegs;
- Syntax10.Scn.Fnt
- BEGIN
- Kernel.RemoveStack (stack.adr);
- IF newSize # 0 THEN Kernel.AddStack (stack.adr, stack.adr - newSize) END
- END SetStackLen;
- Syntax10.Scn.Fnt
- Syntax10i.Scn.Fnt
- (* find mod, refstart, refend, startpc and endpc of a procedure given by a pc *)
- m: Modules.Module;
- ref, p: LONGINT;
- ch: CHAR;
- BEGIN
- m := Modules.modules; mod := NIL; refpos := -1;
- WHILE (m # NIL) & ((pc < m.PC) OR (m.PC+m.codesize*4 < pc)) DO m := m.link END;
- IF m # NIL THEN
- mod := m; pc := (pc - m.PC) DIV 4;
- ref := m.refs; refend := ref; p := 0; startpc := 0;
- IF mod.refs # 0 THEN INC(refend, mod.refsize) END;
- LOOP
- IF ref >= refend THEN EXIT END;
- SYS.GET(ref, ch); INC(ref);
- IF ch = 0F8X THEN
- startpc := 4 * p; RInt(ref, p); endpc := 4 * p;
- IF p > pc THEN refpos := ref; EXIT END
- END
- END
- END SearchProc;
- Syntax10.Scn.Fnt
- VAR p, tmp: Proc;
- BEGIN
- (* invert old *)
- p := old; old := NIL;
- WHILE p # NIL DO tmp := p.up; p. up := old; old := p; p := tmp END;
- p := procs;
- WHILE (old # NIL) & (p # NIL) & (old.sp = p.sp) & (old.beginPC = p.beginPC) DO (* same proc on same stack pos *)
- tmp := p.up;
- old.regs^ := p.regs^;
- p^ := old^;
- p.up := tmp;
- p := p.up; old := old.up
- END;
- (* invert proc *)
- p := procs; procs := NIL;
- WHILE p # NIL DO tmp := p.up; p. up := procs; procs := p; p := tmp END
- END Mix;
- Syntax10.Scn.Fnt
- Syntax10i.Scn.Fnt
- scan stack for procedure information
- Syntax10.Scn.Fnt
- VAR pos, len, instr: LONGINT; trap : Modules.TrapDescPtr;
- BEGIN
- SYS.GET (pc, instr);
- pc := (pc - mod.PC) DIV 4;
- pos := 0; len := 0; IF mod.traps # 0 THEN len := mod.noftraps END;
- trap:= SYS.VAL (Modules.TrapDescPtr, mod.traps);
- WHILE (pos < len) & (pc # trap.offset) DO
- INC(pos);
- trap:=SYS.VAL (Modules.TrapDescPtr, SYS.VAL (LONGINT, trap)+4)
- END;
- IF pos < len THEN
- IF trap.trapno = EnterDebugMode THEN RETURN EnterDebugMode
- ELSIF instr # itw THEN RETURN trap.trapno
- END
- ELSIF instr # itw THEN RETURN OtherTrap
- END;
- RETURN Breakpoint
- END GetTrapClass;
- Syntax10.Scn.Fnt
- FoldElems
- Syntax10.Scn.Fnt
- PictElems
- Alloc
- bc codeseg[2]
- codeseg[0]
- codeseg[1]
- codeseg[2]
- b target
- bc target
- b target
- b next instr
- all other
- restart with instruction 'instr'
- instr =
- instr
- b next instr
- b target
- LR=PC(Instr)+4
- bc codeseg[2](
- codeseg[0]0
- codeseg[1]*
- codeseg[2])i
- b target(
- v bc target){
- b target(
- b next instr(
- f all other(
- restart with instruction 'instr'(
- instr = (
- instr(
- b next instr(
- b target(
- LR=PC(Instr)+4
- Syntax10i.Scn.Fnt
- (*---------------------------------------------------------------------------------------------
- Graphical description
- ----------------------------------------------------------------------------------------------*)
- VAR target: LONGINT; s: SET; val: INTEGER;
- BEGIN
- codeseg[0] := LatestTrapInstr (ctx.spec.PC);
- s := SYS.VAL (SET, codeseg[0]) * {0..5, 30};
- IF s = {1} THEN (* relative branch conditional *)
- target := SYS.VAL (LONGINT, SYS.VAL (SET, codeseg[0]) * {16..29});
- SYS.GET (SYS.ADR (target)+2, val);
- target := val + ctx.spec.PC;
- codeseg[0] := SYS.VAL (LONGINT, SYS.VAL (SET, codeseg[0]) * {0..15, 30, 31} + {28});
- codeseg[2] := SYS.VAL (LONGINT, SYS.VAL (SET, ib) + SYS.VAL (SET, target))
- ELSIF s = {1, 4} THEN (* relative branch unconditional *)
- s := SYS.VAL (SET, codeseg[0]) * {6..29};
- IF 6 IN s THEN s := s + {0..5} END;
- target := ctx.spec.PC + SYS.VAL (LONGINT, s) - SYS.ADR (codeseg[0]);
- codeseg[0] := SYS.VAL (LONGINT, SYS.VAL (SET, ib) + SYS.VAL (SET, target) * {6..29} - {30, 31});
- ctx.spec.LR := ctx.spec.PC + 4
- END;
- codeseg[1] :=SYS.VAL (LONGINT, SYS.VAL (SET, ib) + SYS.VAL (SET, ctx.spec.PC+4));
- ctx.spec.PC := SYS.ADR (codeseg[0]);
- MakeDataExecutable (SYS.ADR (codeseg[0]), 12)
- END SetStartSegment;
- Syntax10.Scn.Fnt
- VAR dummy: Sys.ExceptionHandler;
- BEGIN
- dummy := Sys.InstallExceptionHandler (OldTrap); OldTrap := NIL;
- SetStackLen (0); stack.p := NIL;
- Kernel.RemoveStack (SYS.ADR (regs.reg.R[62]));
- END Uninstall;
- Syntax10.Scn.Fnt
- Syntax10i.Scn.Fnt
- (* stop debugging (precondition: debugMode # 0) *)
- BEGIN
- debugMode := 0;
- debugQ.Handle
- END Stop;
- Syntax10.Scn.Fnt
- BEGIN RETURN debugMode = 2
- END Debugging;
- Syntax10.Scn.Fnt
- BEGIN RETURN debugMode = 1
- END Launching;
- Syntax10.Scn.Fnt
- Syntax10i.Scn.Fnt
- (* TRAP handler *)
- VAR retval, sp: LONGINT; w: Texts.Writer; end: BOOLEAN; p: Proc;
- BEGIN
- IF traplevel # 0 THEN
- traplevel := 0;
- Texts.OpenWriter (w);
- Texts.WriteString (w, "Debug: recursive trap at "); Texts.WriteHex (w, ctx.spec.PC); Texts.WriteLn (w);
- Texts.Append (Oberon.Log, w.buf);
- IF debugMode # 0 THEN Stop END;
- Kernel.Resume (ctx);
- RETURN 0
- END;
- IF ctx.spec.PC = Macintosh.kbdIntPC THEN (* kbd Interrupt *)
- SYS.PUT (Macintosh.kbdIntPC, Macintosh.kbdIntInstr);
- Macintosh.kbdIntPC := 0;
- retval := OldTrap (ctx);
- IF Debugging () THEN Stop END;
- Kernel.Resume (ctx);
- RETURN 0
- END;
- IF Debugging () OR Launching () THEN INC (traplevel); retval := Collect (ctx); DEC (traplevel) ELSE retval := -1 END;
- IF retval # 0 THEN
- MoveRegs (ctx, regs);
- sp := ctx.reg.R[SP];
- stack.size := Kernel.resumeSP - sp;
- SYS.MOVE (sp, stack.adr - stack.size, stack.size); SetStackLen (stack.size);
- ScanStack (regs.spec.PC, sp);
- IF ~Debugging () THEN
- p := procs;
- WHILE p # NIL DO
- p.regs.reg.R[FP] := p.regs.reg.R[FP] - Kernel.resumeSP + stack.adr;
- p := p.up
- END
- END;
- retval := OldTrap (ctx);
- IF Debugging () THEN Stop END;
- Kernel.Resume (ctx)
- END;
- RETURN 0
- END Trap;
- Syntax10.Scn.Fnt
- BEGIN
- IF OldTrap = NIL THEN
- OldTrap := Sys.InstallExceptionHandler (Trap);
- traplevel := 0; debugMode := 0;
- NEW (regs); NEW (regs.spec); NEW (regs.reg); NEW (regs.fp);
- Kernel.AddStack (SYS.ADR (regs.reg.R[62]), SYS.ADR (regs.reg.R[0]));
- NEW (stack.p, StackSize); stack.adr := SYS.ADR (stack.p[0]) + StackSize
- END Install;
- Syntax10.Scn.Fnt
- Syntax10i.Scn.Fnt
- (* prepare debugging (precondition: debugMode = 0) *)
- BEGIN
- debugMode := 1 (* launch debugger mode *)
- END Prepare;
- Syntax10.Scn.Fnt
- BEGIN RETURN regs.spec.PC
- END PC;
- Syntax10.Scn.Fnt
- BEGIN IF procs # NIL THEN procs := procs.up END
- END PopProc;
- Syntax10.Scn.Fnt
- i, j : LONGINT;
- mod : Modules.Module;
- r, rr: LONGINT;
- n : ARRAY 64 OF CHAR;
- BEGIN
- name[0] := 0X;
- SearchProc (startPC, mod, r, rr, i, i);
- IF mod = NIL THEN RETURN END;
- RInt(r, i); RInt(r, i); RInt(r, i); RInt(r, i); RInt(r, i); INC(r);
- RName (r, n);
- COPY (mod.name, name);
- i := 0; WHILE name[i] # 0X DO INC (i) END;
- name[i] := '.';
- j := 0; WHILE n[j] # 0X DO name[i+j+1] := n[j]; INC (j) END;
- name[i+j+1] := 0X
- END FindProc;
- MODULE RTDT; (* Run time debugger: Traphandling; mah 25.10.94 (
- IMPORT Modules, Texts, SYS := SYSTEM, Sys, Oberon, Kernel, Input, Macintosh, Out;
- CONST
- EnterDebugMode* = 255; (* trap number to enter debugmode *)
- Breakpoint = -1; (* trap number of a breakpoint *)
- OtherTrap = -2; (* trap not controlled by debugger *)
- SB = 2*2+1; (* static base register 2 *)
- SP = 1*2+1; (* stack pointer register 1 *)
- FP = 31*2+1; (* frame pointer register 31 *)
- ib = 48000002H;
- itw* = 7FE00008H;
- inop* = 60000000H;
- StackSize* = 50 * 1024; (* size of debugging stack *)
- Proc*=POINTER TO ProcDesc;
- ProcDesc*=RECORD
- debugQ-: Kernel.Queue; (* queue handled when a debuging step has been finished *)
- startQ-: Kernel.Queue; (* queue handled when a debuging step is about to be started *)
- LatestTrapInstr*: PROCEDURE (pc: LONGINT) : LONGINT; (* up-call to fetch instruction at latest position pc *)
- procs-: Proc; (* list of procedures currently on stack *)
- debugMode: INTEGER; (* 0->off, 1->launching, 2->debugging *)
- OldTrap: Sys.ExceptionHandler; (* old system trap handler (Kernel.Trap) only valid if debugging=TRUE *)
- traplevel: INTEGER; (* depth of trap recursion, only valid if debugging=TRUE *)
- regs: Sys.ExceptionInfo; (* current register set of debugged program.*)
- stack: RECORD
- codeseg: ARRAY 3 OF LONGINT; (* dummy codesegment to start next step *)
- dbgPar: Oberon.ParList; (* parameter of debug mode *)
- MakeDataExecutable: PROCEDURE (base, len: LONGINT);
- PROCEDURE ConvertAdr* (VAR adr: LONGINT);
- PROCEDURE RInt (VAR refs: LONGINT; VAR k: LONGINT);
- read integer from reference information
- PROCEDURE RName (VAR refs:LONGINT; VAR name:ARRAY OF CHAR);
- read name from reference information
- PROCEDURE MoveRegs (VAR src, dest: Sys.ExceptionInfo);
- Copies an exception info structure (deep copy)
- PROCEDURE SetStackLen (newSize: LONGINT);
- sets currently used length of the stack copy
- PROCEDURE SearchProc* (pc: LONGINT; VAR mod: Modules.Module; VAR refpos, refend, startpc, endpc: LONGINT);
- PROCEDURE Mix (old: Proc);
- mix new stack description with old one (reuse same memory where possible)
- PROCEDURE ScanStack (pc, sp: LONGINT);
- new, old: Proc;
- ref, refend, p, fsize, psize, ralloc, falloc, calloc, nofFrames: LONGINT;
- leaf: BOOLEAN;
- mod : Modules.Module;
- stackRegs: Sys.ExceptionInfo;
- BEGIN
- nofFrames:=0; old := procs; procs := NIL;
- MoveRegs (regs, stackRegs);
- WHILE (sp <= Kernel.resumeSP) & (nofFrames < 64) DO
- NEW (new); new.up := procs; procs := new;
- new.pc := pc; new.sp := sp;
- MoveRegs (stackRegs, new.regs);
- SearchProc (pc, mod, ref, refend, new.beginPC, new.endPC);
- IF mod = NIL THEN procs := procs.up; Mix (old); RETURN END;
- COPY (mod.name, new.modName);
- IF ref > 0 THEN
- RInt (ref, fsize); RInt (ref, psize); RInt(ref, ralloc);
- RInt (ref, falloc); RInt (ref, calloc);
- SYS.GET (ref, leaf); INC (ref);
- RName (ref, new.name);
- (* new.regs.reg.R[FP] := new.regs.reg.R[FP] - Kernel.resumeSP + stack.adr; *)
- SYS.GET(sp, sp);
- IF leaf THEN pc := stackRegs.spec.LR ELSE SYS.GET(sp+8, pc) END;
- p := sp - (31 - ralloc) * 4;
- WHILE ralloc < 31 DO INC (ralloc); SYS.GET (p, stackRegs.reg.R[2*ralloc+1]); INC (p, 4) END;
- INC (p, (-p) MOD 8);
- WHILE falloc < 31 DO INC (falloc); SYS.GET (p, stackRegs.fp.R[2*falloc+1]); INC (p, 8) END;
- IF calloc < 19 THEN SYS.GET (sp+4, stackRegs.spec.CR) END
- ELSE
- SYS.GET (sp, sp); SYS.GET (sp + 8, pc)
- END;
- IF (new.name = "Loop") & (new.modName = "Oberon") THEN Mix (old); RETURN END;
- INC (nofFrames)
- END ScanStack;
- PROCEDURE GetTrapClass (mod: Modules.Module; pc: LONGINT) : INTEGER;
- PROCEDURE SetStartSegment (VAR ctx: Sys.ExceptionInfo);
- generate dummy code segment to skip initial bp
- PROCEDURE Collect (VAR ctx: Sys.ExceptionInfo) : LONGINT;
- sp, refpos, refend, dummy: LONGINT;
- mod: Modules.Module;
- class, x, y: INTEGER;
- keys: SET;
- BEGIN
- IF debugMode = 0 THEN RETURN -1 END;
- SearchProc (ctx.spec.PC, mod, refpos, refend, dummy, dummy);
- IF (ctx.kind # 2) OR (mod = NIL) THEN RETURN -1 END;
- class := GetTrapClass (mod, ctx.spec.PC);
- IF (class # EnterDebugMode) & (class # Breakpoint) THEN RETURN -1 END;
- IF class = Breakpoint THEN
- debugMode := 2;
- dbgPar.text := Oberon.Par.text; dbgPar.pos := Oberon.Par.pos;
- sp := ctx.reg.R[SP];
- MoveRegs (ctx, regs);
- stack.size := Kernel.resumeSP-sp;
- SYS.MOVE (sp, stack.adr - stack.size, stack.size);
- SetStackLen (stack.size);
- ScanStack (regs.spec.PC, sp);
- debugQ.Handle;
- Kernel.Resume (ctx);
- RETURN 0
- END;
- startQ.Handle;
- Oberon.Par.pos := dbgPar.pos; Oberon.Par.text := dbgPar.text;
- MoveRegs (regs, ctx);
- SYS.MOVE (stack.adr - stack.size, Kernel.resumeSP - stack.size, stack.size);
- SetStartSegment (ctx);
- RETURN 0
- END Collect;
- PROCEDURE Uninstall*;
- PROCEDURE Stop*;
- PROCEDURE Debugging* () : BOOLEAN;
- PROCEDURE Launching* () : BOOLEAN;
- PROCEDURE Trap (ctx: Sys.ExceptionInfo) : LONGINT;
- PROCEDURE Install*;
- PROCEDURE Prepare*;
- PROCEDURE PC* () : LONGINT;
- PROCEDURE PopProc*;
- PROCEDURE FindProc* (startPC: LONGINT; VAR name: ARRAY OF CHAR);
- Get name of procedure starting at startPC
- BEGIN
- debugQ.Init; startQ.Init; OldTrap := NIL; NEW (dbgPar);
- Sys.Assign ("MakeDataExecutable", SYS.ADR (MakeDataExecutable))
- END RTDT.
-